<?php

namespace App\Kuafu\Shop\Service;

use App\Kuafu\Base\Service\BaseService;
use App\Kuafu\Common\Service\OssService;
use App\Kuafu\Config\Model\ConfigModel;
use App\Kuafu\Shop\Enum\CameraCacheEnum;
use App\Kuafu\Shop\Enum\CodeEnum;
use App\Kuafu\Shop\Enum\ShopCodeEnum;
use App\Kuafu\Shop\Exceptions\CameraException;
use App\Kuafu\Shop\Model\CameraModel;
use App\Kuafu\User\Exceptions\UserException;
use App\Kuafu\User\Service\AuthService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use OSS\Core\OssException;

class CameraService extends BaseService
{
    /**
     * 摄像头列表
     *
     * @param int $shopId
     * @param int $isCache
     * @return Builder[]|Collection
     */
    public static function getCameraList(int $shopId, int $isCache = 1)
    {
        if ($isCache) {
            return Cache::remember(CameraCacheEnum::getCameraListCacheKey($shopId), getSwitchCacheTime(1200),
                function () use ($shopId) {
                    return self::getCameraListNotCache($shopId);
                });
        } else {
            return self::getCameraListNotCache($shopId);
        }
    }

    /**
     * 摄像头列表-直接取数据库
     * @param int $shopId
     * @return Builder[]|Collection
     */
    public static function getCameraListNotCache(int $shopId)
    {
        return CameraModel::query()
                          ->where('deviceType', CameraModel::DEVICE_TYPE_CAMERA)
                          ->where('shopId', $shopId)
                          ->whereIn('tripleType', [0, CodeEnum::SHOP_CAMERA_TRIPLE_TYPE_1])
                          ->select([
                              'id',
                              'shopId',
                              'type',
                              'name',
                              'serialNo',
                              'deviceName',
                              'mac',
                              'status',
                              'productKey',
                              'supplier',
                          ])
                          ->get();
    }


    /**
     * @param string $streamUrl
     * @param int $shopId
     * @param int $cameraId
     * @return array
     * @throws OssException
     */
    public static function screenShotFromStream(string $streamUrl, int $shopId, int $cameraId): array
    {
        $suffix   = '.jpg';
        $fileName = Str::uuid()->toString() . "{$suffix}";

        if (!Storage::disk('public')->exists('cameraImages')) {
            Storage::disk('public')->makeDirectory('cameraImages');
        }

        $filePath = storage_path('app/public/cameraImages/' . $fileName);
//        $filePath = './' . $fileName;

        $ffmpegCmd = "ffmpeg -i '{$streamUrl}' -y -f mjpeg -t 0.001 {$filePath}";
//        $ffmpegCmd = "ffmpeg -i '{$streamUrl}' {$filePath} -ss 00:00:02  -r 1 -vframes 1 -an -vcodec mjpeg";

//        ffmpeg -i xxx sample.jpg -ss 00:00:05  -r 1 -vframes 1 -an -vcodec mjpeg


        $output    = [];
        $returnVar = 0;

        exec($ffmpegCmd, $output, $returnVar);
//        dd($ffmpegCmd);

        if ($returnVar !== 0) {
            $errMsg = 'ffmpeg拉取异常';
            // todo error
            Log::error($errMsg, [
                'output'    => $output,
                'returnVal' => $returnVar,
            ]);
            if (File::exists($filePath)) {
                File::delete($filePath);
            }

//            throw new \Exception($errMsg);
            return [];
        }

        if (!File::exists($filePath)) {
            $errMsg = 'ffmpeg拉取异常,文件未生成';
            //todo error
            Log::error($errMsg, [
                'output'    => $output,
                'returnVal' => $returnVar,
            ]);
            throw new \Exception($errMsg);
        }

        $date           = date('Y-m-d');
        $uploadFileName = date('YmdHis') . mt_rand(100, 999) . "{$suffix}";
        $savePath       = "cameraImages/{$shopId}/{$cameraId}/{$date}/{$uploadFileName}";

        $uploadedInfo = OssService::uploadFile($filePath, $suffix, $savePath);

//        if (File::exists($filePath)) {
//            File::delete($filePath);
//        }
        return $uploadedInfo;
    }

    /**
     *
     *
     * @param $shopInfo
     * @return void
     * @throws CameraException
     * @throws UserException
     */
    public static function checkCameraLimit($shopInfo)
    {
        $cameraConfig = ConfigModel::getConfigByTypeKeyOne('merchant', 'cameraConfig', 60);
        $cameraConfig = json_decode($cameraConfig->value, 1);

        if (empty($cameraConfig) || !isset($cameraConfig['maintainList'][$shopInfo['cameraSupplier'] ?? 0])) {
            return;
        }

        // 是否全站监控维护
        if ($cameraConfig['isAllMaintain']) {
            throw new CameraException(ShopCodeEnum::ERR_NO_ACCESS_ERROR, $cameraConfig['maintainText']);
        }

        // 单平台监控维护
        if ($cameraConfig['maintainList'][$shopInfo['cameraSupplier']]) {
            throw new CameraException(ShopCodeEnum::ERR_NO_ACCESS_ERROR, $cameraConfig['maintainText']);
        }

        // 只针对阿里云限流控制
        if ($shopInfo->cameraSupplier == CameraModel::SUPPLIER_ALIYUN) {
            $userId = AuthService::getUserId(false);
            self::aliyunCameraLimit($userId, $cameraConfig);
        }

    }


    /**
     * 阿里云单用户限制
     *
     * @param int $userId
     * @param array $cameraConfig
     * @return void
     * @throws CameraException
     */
    public static function aliyunCameraLimit(int $userId, array $cameraConfig)
    {
        if (!$cameraConfig['specialAliyunMaintain']) {
            return;
        }
        $limitConfig = $cameraConfig['specialAliyunLimitConfig'];

        $key    = "aliyunCameraLimit_2nd";
        $window = $limitConfig['uvMinutes'] * 60; // 时间窗口为 300 秒（5分钟）

        $currentTime = time();
        $windowStart = $currentTime - $window;

        $redis = Redis::connection();
        // 获取当前时间窗口内的用户数量
        $currentUsersCount = $redis->zCount($key, $windowStart, $currentTime);

        if ($redis->zScore($key, $userId) !== false && $redis->zScore($key, $userId) >= $windowStart) {
            return;
        }

        if ($currentUsersCount < $limitConfig['uv']) {
            // 如果当前用户数小于3，添加用户到集合
            $redis->zAdd($key, $currentTime, $userId);
            return;
        } else {
            throw new CameraException(ShopCodeEnum::ERR_NO_ACCESS_ERROR,
                $cameraConfig['specialAliyunMaintainText']);
        }
    }
}
